package com.step;

import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;

import android.opengl.GLSurfaceView.Renderer;
import android.opengl.GLU;

import com.step.Step.Dimension;

/**
 * 渲染类，负责图像显示。
 * 
 * @author heop
 * 
 */
public class GameRenderer implements Renderer {
	public static final int NUM_GLLIGHTS = 8;
	private GL10 gl;
	private IGameView renderer;
	private int width;
	private int height;
	private float startTime = System.nanoTime();
	private float deltaTime;
	
	public GameRenderer(IGameView renderer) {
		this.renderer = renderer;
	}

	public void onDrawFrame(GL10 gl) {
		//Step.log(Step.TAG, "Graphics.onDrawFrame()");
		deltaTime = (System.nanoTime()-startTime) / 1000000000.0f;
   startTime = System.nanoTime();
		gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
		// update 
		if(renderer == null) throw new RuntimeException("Graphics:应用没有初始化，必须先在onCreate()方法内调用Game.initialize()方法");
		renderer.update();
		if(Step.enableFps) doFps();
	}
	
	private long frameCount = 0;
	private float fps = 0;
	private long timeLastSample;
	private static final int FRAMERATE_SAMPLE_INTERVAL = 5000; 
	
	private void doFps(){
		frameCount++;

		long now = System.currentTimeMillis();
		long delta = now - timeLastSample;
		
		if (delta >= FRAMERATE_SAMPLE_INTERVAL)	{
			fps = frameCount / (delta/1000f); 
			Step.log(Step.TAG, "Graphics.FPS:"+Math.round(fps)+" memory:"+Step.getJavaHeap() +"/"+ Step.getNativeHeap()+"Bytes");
			timeLastSample = now;
			frameCount = 0;
		}
	}
	
	public void onSurfaceChanged(GL10 gl, int width, int height) {
		Step.log(Step.TAG, "Graphics.onSurfaceChanged()");
		this.width = width;
		this.height = height;
		Step.aspectRatio = (float) width / (float)height;
		this.gl = gl;
		
		// TODO:更新视窗
		gl.glViewport(0, 0, width, height);
		gl.glMatrixMode(GL10.GL_PROJECTION);
		gl.glLoadIdentity();
		//gl.glOrthof(-width/2, width/2, -height/2, height/2, 1, -1);
		if(Step.dimension == Dimension.d2d){
			gl.glOrthof(-Step.aspectRatio, Step.aspectRatio, -1, 1, 1, -1);
		}
		else{
			GLU.gluPerspective(gl,30.0f, Step.aspectRatio, 1.0f, 10.0f);
		}
		
		gl.glMatrixMode(GL10.GL_MODELVIEW);
		gl.glLoadIdentity();
	}

	public void onSurfaceCreated(GL10 gl, EGLConfig eglConfig) {
		Step.log(Step.TAG, "Graphics.onSurfaceCreated()");
		this.gl = gl;
		Step.gl = gl;
		resetGL();
		renderer.create();
	}

	private void resetGL() {
		// TODO:Reset TextureManager
		// Shared.textureManager().reset();

		// Do OpenGL settings which we are using as defaults, or which we will
		// not be changing on-draw
		// 启用阴影平滑
		gl.glShadeModel(GL10.GL_SMOOTH);
		   
		// Explicit depth settings
		gl.glEnable(GL10.GL_DEPTH_TEST);		
		gl.glClearDepthf(10.0f);
		gl.glDepthFunc(GL10.GL_LEQUAL);
		gl.glDepthRangef(0, 10f);
		gl.glDepthMask(true);
		// 对透视进行修正
		gl.glHint(GL10.GL_PERSPECTIVE_CORRECTION_HINT, GL10.GL_FASTEST);
		
		// Alpha enabled
		gl.glEnable(GL10.GL_BLEND);
		gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
		
		// "Transparency is best implemented using glBlendFunc(GL_SRC_ALPHA,
		// GL_ONE_MINUS_SRC_ALPHA)
		// with primitives sorted from farthest to nearest."

		// Texture
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER,	GL10.GL_NEAREST); // (OpenGL default is GL_NEAREST_MIPMAP)
		gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER,	GL10.GL_LINEAR); // (is OpenGL default)

		// CCW frontfaces only, by default
		// TODO:fix it
		
		gl.glFrontFace(GL10.GL_CCW); // 设置逆时针方向的面为正面，GL_CW为顺时针方向面为正面。
		gl.glCullFace(GL10.GL_BACK); // 禁用多边形背面上的光照、阴影和颜色计算及操作，消除不必要的渲染计算。
		gl.glEnable(GL10.GL_CULL_FACE);// 开启剔除操作，例如对象位置变化时，我们只能看到构成其组成的某一面
		
		// Disable lights by default		
		for (int i = GL10.GL_LIGHT0; i < GL10.GL_LIGHT0 + NUM_GLLIGHTS; i++) {
			gl.glDisable(i);
		}
		
		// 总是允许顶点数组
		gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);		
	}

	public GL10 getGL() {
		return gl;
	}

	public void setGL(GL10 gl) {
		this.gl = gl;
	}

	public float getFps() {
		return fps;
	}

	public void setFps(float fps) {
		this.fps = fps;
	}

	public int getWidth() {
		return width;
	}

	public void setWidth(int width) {
		this.width = width;
	}

	public int getHeight() {
		return height;
	}

	public void setHeight(int height) {
		this.height = height;
	}
	
	public float getDeltaTime(){
		return deltaTime;
	}
}
